/*
	Copyright (C) 2008 by Jean-FranÁois Geyelin
	jfgeyelin@gmail.com

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the
	Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/



#include "Player.h"
#include "DrawObject.h"
#include "globals.h"
#include "SurfaceHandler.h"
#include "BlackExplosion.h"
#include "Shield.h"


Player::Player(float x_, float y_):MovingObject(x_,y_,27,46,6,26,14,17){// MovingObject(x_,y_,17,19,5,26){



	respawnX = x;
	respawnY = y;

    inertiaX = 0;
	numberOfFrame=4;
	frame = 0;
	timeLeftUntilNextFrame = 2;
	direction = RIGHT;
	isJumping = false;
	timeLeftTillComingDown = 0;
	numberOfCoins = 0;
	numberOfLives = 0;
    numberOfPoints = 0;

	sprites = new SplittedSurface("shyguy.png",10);
	spritesNoShield = new SplittedSurface("shyguy_no_shield.png",10);

	aureoleSprites = new SplittedSurface("aureole.png",1);
	spearSprites = new SplittedSurface("spear.png",2);
	attackingSprites = new SplittedSurface("shyguy_no_spear.png",2);
	attackingSpritesNoShield = new SplittedSurface("shyguy_no_spear_no_shield.png",2);
	deadSprites = new SplittedSurface("ghost_player.png",4);
    spritesHarmlessSprites = new SplittedSurface("shyguy_normal.png",10);
    jaugeSprites = new SplittedSurface("jauge.png",21);


    for (int i=0;i<4;i++)
	SDL_SetAlpha(deadSprites->get(i), SDL_SRCALPHA, 128);






    hasShield = false;
	hasSpear  = false;
	isInvincible = false;
	invincibleTimeLeft = 0;
	isAttacking = false;
	attackingAngle = 0;
	canAttack = true;
	canJump = false;
	alive = true;
	deadFrame= 0;
	hasFinishedLevel = false;
	canMove = true;
	pauseJustAfterTheDeath = false;
	depth = PLAYER_DEPTH;

	isOnFracktail = false;
	slowMo = false;

    typeOfMovingObject=PLAYER_MO;

}

Player::~Player(void) {
	delete sprites;
	delete spritesNoShield;
	delete aureoleSprites;
	delete spearSprites;
	delete attackingSprites;
	delete attackingSpritesNoShield;
	delete deadSprites;
	delete spritesHarmlessSprites;
	delete jaugeSprites;
}



void Player::draw(void) {
    if (isOnFracktail)
    return;


    if (slowMo) {
        if (slowMoTime<420)
        DrawObject::simplyDraw(x+4,y,jaugeSprites->get(slowMoTime/20));

    }


	if (alive) {
		if (isInvincible) {
            char yy[] = {0,1,1,1,0,-1,-1,-1};
            SDL_SetAlpha(aureoleSprites->get(0), SDL_SRCALPHA, 20+(invincibleTimeLeft*255)/250);
            DrawObject::simplyDraw(x+(direction==LEFT?5:8),y+17+yy[(invincibleTimeLeft/3)%8],aureoleSprites->get(0));
		}
		if (hasSpear) {

			if (!isAttacking) {
			    if (hasShield)
				DrawObject::simplyDraw(x,y,sprites->get(frameToBeDrawn));
				else
				DrawObject::simplyDraw(x,y,spritesNoShield->get(frameToBeDrawn));
			}
			else
			{
				int n = (direction==LEFT?0:1);

				if (hasShield)
				DrawObject::simplyDraw(x+2,y+18,attackingSprites->get(n));
				else
				DrawObject::simplyDraw(x+2,y+18,attackingSpritesNoShield->get(n));

		    	SDL_Surface *temp = SDL_CreateRGBSurface(SDL_HWSURFACE, 64, 64, 32, bmask, gmask, rmask, amask);

		    	SDL_Rect r;
		    	r.x = 0;
		    	r.y = 0;
		    	r.w = 64;
		    	r.h = 64;


                #define DRAW_SPEAR(aangle,ttransparency)\
				SDL_FillRect(temp, &r,transparentColor);\
				my_sge_transform(spearSprites->get(n), temp, (direction==LEFT?-attackingAngle+aangle:attackingAngle-aangle), 1,1, 16, 30, 32, 32, 0);\
				SDL_SetColorKey(temp, SDL_SRCCOLORKEY|SDL_RLEACCEL, transparentColor);\
				SDL_SetAlpha(temp, SDL_SRCALPHA, ttransparency);\
				SurfaceHandler::drawSurface(temp,((int)x)-camera->getX()-20,((int)y)-camera->getY()+3);


                for (int j=100;j>0;j-=10) {
                    DRAW_SPEAR(j,(100-j)*2)
                }

                DRAW_SPEAR(0,255)



                #undef DRAW_SPEAR





				SDL_FreeSurface(temp);
			}




    DRAW_IN_CASE_OF_DEBUG


		}
		else
		{
			DrawObject::simplyDraw(x,y,spritesHarmlessSprites->get(frameToBeDrawn));
		}
	}
	else
	{
		if (pauseJustAfterTheDeath) {
            DrawObject::simplyDraw(x+collisionX,y+collisionY,deadSprites->get(frameToBeDrawn));
		}
		else
		{
			DrawObject::simplyDraw(x+collisionX,y+collisionY,deadSprites->get(frameToBeDrawn));
		}
	}
	//DrawObject::drawRect(this);


}


void Player::handleCollisionWithObject(Object *o) {
}

void Player::setCanMove(bool v) {
	canMove = v;
}

void Player::setVxVy(void) {
//    PRINTF2("il bouge: %f - %f\n",x,y);

    if (slowMo) {
        slowMoTime--;
        if (slowMoTime<=0)
        slowMo = false;
    }

    if (!canMove) {
        keyPressed->setKeys(0);
    }



	if (alive) {

	    if (!isOnFracktail) {
            vx=0;
            bool b=hasGroundUnderneath();
            y--;
            b|=hasGroundUnderneath()|canJump;

            if (canJump) {canJump=false;}

            if (b) {
                canAttack = true;
            }


            float SPEED;

            if (hasSpear)
            SPEED = 3;
            else
            SPEED = 2;

            bool isTryingToMove = false;
            if( keyPressed->right) {
                vx=SPEED;

                direction = RIGHT;
                isTryingToMove = true;
            }
            if( keyPressed->left) {
                vx=-SPEED;
                direction = LEFT;
                isTryingToMove = true;
            }


            if (keyPressed->action && !isAttacking && canAttack && hasSpear) {
                vy-=3;
                attackingAngle=0;
                isAttacking = true;
                canAttack = false;
                allSounds->play("swish");
            }

            if (isAttacking) {
                attackingAngle+=30;
                if (attackingAngle>=380)
                isAttacking = false;
            }

            timeLeftUntilNextFrame--;
            if (!timeLeftUntilNextFrame) {
                frame++;
                if (frame > numberOfFrame-1)
                frame = 0;
                timeLeftUntilNextFrame = 4*2;
            }

            y++;

            if( keyPressed->jump) {
                if (b) {
                    vy=-1.0;//-1.0;//-1.7;
                    isJumping = true;
                    timeLeftTillComingDown=10;
                    allSounds->play("jump");
                }
                else
                {
                    if (isJumping) {

                        timeLeftTillComingDown--;
                        if (timeLeftTillComingDown==0 || vy>=0 || isAttacking) {
                            isJumping=false;
                        }
                        else
                        vy=-4;

                    }
                }
            //isComingDown = false;
            //timeLeftTillComingDown = 0;
            }
            else
            {
                if (isJumping) {
                    isJumping=false;
                }
            }

            if (isTryingToMove == false)
            frame = 0;
            if (b)
            frameToBeDrawn = frame + (direction==RIGHT?5:0);
            else
            frameToBeDrawn = 3 + (direction==RIGHT?5:0);
	    }
	    else {
	    //is on fracktail
            vx=0;
            if (keyPressed->left)
            fracktail->setAngle(fracktail->getAngle()-0.04);
            if (keyPressed->right)
            fracktail->setAngle(fracktail->getAngle()+0.04);
	    }
	}
	else
	{
	    vx = 0;
		vy = 0;
		if (pauseJustAfterTheDeath) {
            timeOfPauseJustAfterTheDeath--;
            if (timeOfPauseJustAfterTheDeath==0)
            pauseJustAfterTheDeath = false;
		}
		else
		{

			#define SEUIL   18/2
			#define MOVE_TO(a,aSpawn)\
			{\
				float hihi = (aSpawn-a)/15;\
				if (abs((int)hihi)>SEUIL) {\
					if (hihi<0) {\
						a-=SEUIL;\
					}\
					else\
					{\
						a+=SEUIL;\
					}\
				}\
				else\
				a+=hihi;\
			}
			MOVE_TO(x,respawnX)
			MOVE_TO(y,respawnY)
			if (abs(int(x-respawnX))<5 && abs(int(y-respawnY))<5) {
				setAlive(true);
			    new BlackExplosion(respawnX+collisionX+width/2 - 10,respawnY+collisionY+height/2 - 10);//
			}
			#undef MOVE_TO
			#undef SEUIL
			frameToBeDrawn = (respawnX-x>0?0:2);
			deadFrame--;
	  		if (deadFrame<=0)
			deadFrame=18;
			if (deadFrame>9)
			frameToBeDrawn++;
		}
	}

//	if (keystates[ SDLK_DOWN ]) {

//	}


	inertiaX += (vx-inertiaX)*0.080;//0.20;
	vx = inertiaX;

	invincibleTimeLeft--;
	if (invincibleTimeLeft==0) {
        isInvincible = false;
	}
}

void Player::setVy(float vy_) {
	vy=vy_;
}

void Player::setVx(float vx_) {
    inertiaX = vx_;
}

int Player::getNumberOfCoins(void) {

	while (numberOfCoins>100) {
		increaseNumberOfLives();
		numberOfCoins-=100;
	}

	return numberOfCoins;
}

void Player::setNumberOfCoins(int n) {
	numberOfCoins = n;
}

void Player::increaseNumberOfCoins(void) {
	numberOfCoins++;
	numberOfPoints+=50;
}

int Player::getNumberOfLives(void) {
	return numberOfLives;
}

void Player::setNumberOfLives(int n) {
	numberOfLives = n;
}

void Player::increaseNumberOfLives(void) {
	numberOfLives++;
}

void Player::increaseNumberOfPoints(int n) {
    numberOfPoints += n;
}

void Player::setNumberOfPoints(int n) {
    numberOfPoints = n;
}

int Player::getNumberOfPoints(void) {
    return numberOfPoints;
}


void Player::setCanJump(void) {
	canJump = true;
}

bool Player::isAlive(void) {
	return alive;
}

void Player::setHasSpear(bool b) {
    hasSpear = b;
}

void Player::kill(void) {

    deadFrame = 0;
    frameToBeDrawn = 0;
    alive = false;
    numberOfLives--;
    pauseJustAfterTheDeath = true;
    timeOfPauseJustAfterTheDeath = 30;

}

void Player::setAlive(bool b) {
	if (!b) {
		if (isInvincible)
		return;
		if (!hasShield) {
            if (alive) {
                kill();
            }
		}
		else {
            hasShield = false;

            Shield *s=new Shield(x+10,y+10,true,direction);
            s->setVy(-3);
            s->setPermanentlyTheVx(inertiaX);

            isInvincible = true;
            invincibleTimeLeft = 200;
            return;
		}
	}
	else {
	    hasShield = hasSpear;
        isInvincible = true;
        invincibleTimeLeft = 200;
	}
	alive = b;
}




void Player::killNoMatterWhat(void) {
	if (alive) {
		kill();
	}
}



void Player::setRespawn(float x_, float y_) {
	if (!alive)
	return;
	respawnX = x_;
	respawnY = y_;
}

bool Player::getHasSpear(void) {
	return hasSpear;
}

bool Player::getHasShield(void) {
	return hasShield;
}

void Player::setCanAttack(bool b) {
	canAttack = b;
}


DIRECTION Player::getDirection(void) {
    return direction;
}

void Player::setHasShield(bool b) {
    hasShield = b;
}

bool Player::shouldUseSpear(void) {
    return (vy == -3.750) && (timeLeftTillComingDown==0) && canAttack && hasSpear;
}

bool Player::spearIsHittingThisObject(Object *o) {
//        #error fonction a programmer
        if (!isAttacking)
        return false;


        Point point;
        float middleX = collisionX+(collisionWidth/2);
        float middleY = collisionY+(collisionHeight/2);


        #define TEST_SPEAR(aangle,rayon)\
                {point.x = (int)(middleX+(direction==LEFT?rayon*cos(aangle):-rayon*cos(aangle)));\
                point.y = (int)(middleY-rayon*sin(aangle));\
                r|=isPointColliding(o,point);\
                }


        bool r=false;
        float a;
        for (float j=attackingAngle;j<=attackingAngle+100;j+=20) {
            a = (j*2*PI)/360;
            TEST_SPEAR(a,28)
            TEST_SPEAR(a,14)
        }
        #undef TEST_SPEAR


        return r;

}

void Player::setIsOnFracktail(bool b) {
    isOnFracktail = b;
}

void Player::setFracktail(Fracktail *fracktail_) {
    fracktail = fracktail_;
}

bool Player::getIsOnFracktail(void) {
    return isOnFracktail;
}

bool Player::isInSlowMotion(void) {
    return slowMo;
}

void Player::setSlowMotionTime(int slowMoTime_) {
    slowMo = true;
    slowMoTime = slowMoTime_;
}
